Plan
-
Retour TP1
-
Premiers patrons
Retour TP1
# -*- coding: utf-8 -*-
# usage: ruby noteModel.rb [directory] [file]
MODEL_NAME = ARGV[1] ? ARGV[1] : "TP1.uml"
NOTES_FILE = "notes.csv"
studentDirectory = ARGV[0] ? ARGV[0] : "."
studentModelFileName = studentDirectory+"/"+MODEL_NAME
puts "Checking " + studentModelFileName
$assertFileContains = [
/@startuml/m,
/@enduml/m,
/abstract Personnage/m,
/Personnage\s+--> ".*" ComportementArme/m,
/interface\s+ComportementArme/m,
/ComportementArme\s+<\|\.\./m,
]
notestr = ""
# test file
notestr += (File.exists?(studentModelFileName)) ? '.' : 'F'
# test file contents
fileContent = File.read(studentModelFileName)
$assertFileContains.each {|re|
notestr += (fileContent =~ re) ? '.' : 'F'
}
# status
result = notestr.gsub('F','').size.to_s+'/'+notestr.size.to_s+";\n"
bilan = ARGV[0]+';'+notestr+';'+result
print notestr
print result
destfile = File.new(NOTES_FILE,"a")
destfile.write(bilan)
destfile.close()
| Moyenne: 11/20 !! |
Retour TP1 (suite)
| Attendus |
70 |
| Rendus |
43 (61%) ⇒ 27 |
| Nom OK |
16 (37% des rendus) ⇒ 16 Exemple de noms : |
| 20/20 |
31 |
| 17/20 |
5 |
| 14/20 |
2 |
| 11/20 |
1 |
| 09/20 |
2 |
| 03/20 |
2 |
| Moy. |
11/20 |
Exemples de bons principes
SOLID:
-
Single Responsibility Principle
-
Open-Closed Principle
-
Liskov Substitution Principle
-
Interface Segregation Principle
-
Dependency Inversion Principle
Single Responsibility Principle
Responsabilité => Sujet à changement
Open-Closed Principle
Ouvert à l'extension mais fermé à la modification
Open-Closed Principle (suite)
Ainsi, une fois écrite et testée, une classe ne devrait être modifiée que pour être corrigée! Toute modification devrait être possible par extension.
Liskov Substitution Principle
LSP : le principe
Une classe doit pouvoir être remplacée par une instance d'un de ses sous-types, sans modifier la cohérence du programme
LSP : un exemple
Un carré est un rectangle a deux côtés égaux.
|
Question
Peut-on toujours substituer un Carré à la place d’un Rectangle ?
|
Vraiment?
Rectangle.java)class Rectangle
{
protected int m_width;
protected int m_height;
public void setWidth(int width){
m_width = width;
}
public void setHeight(int height){
m_height = height;
}
public int getWidth(){
return m_width;
}
public int getHeight(){
return m_height;
}
public int getArea(){
return m_width * m_height;
}
}
Vraiment?
Square.java)// Violation of Likov's Substitution Principle
class Square extends Rectangle
{
public void setWidth(int width){
m_width = width;
m_height = width;
}
public void setHeight(int height){
m_width = height;
m_height = height;
}
}
Vraiment?
Square.java - suite)class LspTest
{
private static Rectangle getNewRectangle()
{
// it can be an object returned by some factory ...
return new Square();
}
public static void main (String args[])
{
Rectangle r = LspTest.getNewRectangle();
r.setWidth(5);
r.setHeight(10);
// User knows that r is a rectangle.
// It assumes that he's able to set the width and height as for the base class
System.out.println(r.getArea());
// Now she's surprised to see that the area is 100 instead of 50.
}
}
Et l’inverse?
Même problème
Rectangle.java)class LspTest
{
private static Square getNewSquare()
{
// it can be an object returned by some factory ...
return new Rectangle();
}
public static void main (String args[])
{
Square s = LspTest.getNewSquare();
s.setWidth(5);
// User knows that r is a rectangle.
// It assumes that he's able to set the width and height as for the base class
System.out.println(s.getArea());
// Now she's surprised to see that the area is 0 instead of 25.
}
}
Interface Segregation Principle
Préférer plusieurs interfaces spécifiques pour chaque client plutôt qu'une seule interface générale
Dependency Inversion Principle
Il faut dépendre des abstractions, pas des implémentations
DIP : explications
Ce principe indique :
-
Les modules de haut niveau (abstraits) ne doivent pas dépendre des modules de bas niveau. Les deux doivent dépendre d’abstractions.
-
Les abstractions ne doivent pas dépendre des détails d’implémentation. C’est l’inverse : les détails doivent dépendre des abstractions.
| Ainsi ce principe va à l’encontre de l’intuition classique. |
Exemple (bad)
Exemple (good)
SOLID et patrons
|
QUESTION
Lesquels des 5 principes SOLID s’appliquent bien à Strategy ? |
SOLID et patrons (éléments de réponses)
GRASP
The critical design tool for software development is a mind well educated in design principles. It is not the UML or any other technology.
2005
Il s’agit d’un ensemble de patrons, plutôt orientés conception (UML). Nous en aborderons certains au travers des exemples de ce module (cf. [Larman05]).
Les patrons : comment ça marche ?
Intérêt
-
Réponses éprouvées à des problèmes récurrents
-
Vocabulaire commun
T’as qu’Ã utiliser une factory!
|
QUESTION
Qui fait la nuit de l’info ? |
Éléments de définition
-
Nom
-
Problème
-
Solution
-
Conséquences
Exemple pour Strategy :
- Nom
-
Strategy
- Problème
-
Situations où il est nécessaire de pouvoir définir dynamiquement les algorithmes utilisés.
- Solution
-
Définir une famille d’algorithmes, encapsuler chacun d’eux en tant qu’objet, et les rendre interchangeables.
- Conséquences
-
Ce patron laisse les algorithmes changer indépendamment des clients qui les emploient.
Singleton
Principes de conception
| Pas de nouveau principes de conception particuliers pour le patron [singleton] |
Patron Singleton
|
Design pattern : Singleton
Singleton garantit qu’une classe n’a qu’une seule instance et fournit un point d’accès global à cette instance. |
Exemples d’utilisation du patron Singleton
Quelques exemple de l’utilisation industrielle de [singleton] :
-
Thread pools (pour contrôler les threads)
-
Connexions SQL
-
Objets de type Registry
-
Objets gérant les préférences utilisateur
-
Caches
-
Les classes Factory
-
…
Implémentations Java du patron Singleton
Pour résumer les (bonnes) implémentations Java :
-
Initialisation directe de la variable instance.
-
Initialisation dans un bloc
static. -
Utilisation d’un
enumà la place d’une classe.
Initialisation directe de la variable instance
public final class Singleton {
private final static volatile Singleton instance = new Singleton();
public final static Singleton getInstance() { return instance; }
private Singleton() {}
}
| On n’a pas vu cette implémentation en TD! |
Initialisation dans un bloc static
public final class Singleton {
private static volatile Singleton instance = null;
static {
instance = new Singleton();
}
public final static Singleton getInstance() { return instance; }
private Singleton() {}
}
Utilisation d’un enum
public enum Singleton {
SINGLETON;
public static Singleton getInstance() { return SINGLETON; }
}
|
Exemple d’utilisation d’un enum
Exemple d’utilisation de ce type d’implémentation
public enum MonSingleton {
INSTANCE;
private String attribute = "World";
public String sayHello() {
return "Hello " + attribute;
}
}
Et on l’appelle avec :
MonSingleton.INSTANCE.sayHello();
Pourquoi un enum ?
Intérêts/Limites d’utiliser un enum :
-
les enumérations classiques sont thread-safe car elles sont initialisées par le classloader
-
on ne peut pas utiliser l’héritage
Time for a quizz!
|
QUESTION
|